import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * 
 * @author David Mitchell
 * @version v 0.1
 * This is the Boards that are assigned to each indivial character
 * The boards are there to set up each space, and change the 
 * state of each space as there is different effects to it.
 *
 */

public class Board extends JPanel  {
	/*
	 * When the ships are set up, we will want to make sure 
	 * that we go ahead and decide the size and the name of each ship.
	 */
	/**
	 * @author David Mitchell
	 */
	public Board(boolean player){
		placedShips = 0;
		deadShips=0;
		debugMode = false;
		this.player = player;
		
		spaces = new Space[BOARD_SIZE][BOARD_SIZE];
		ships = new Ship[NUM_OF_SHIPS];
		
		setLayout(new GridLayout(BOARD_SIZE, BOARD_SIZE));
		for(int y = 0; y < BOARD_SIZE; y++){
			for(int x = 0; x < BOARD_SIZE; x++){
				spaces[y][x] = new Space();
				this.add(spaces[y][x]);
			}
		}
		
		// Because Battleship doesn't have any 
		// dynamic rules we simply hard coded
		// the Ships into the Array. 
		ships[0] = new Ship("Aircraft carrier", 5);
		ships[1] = new Ship("Battleship", 4);
		ships[2] = new Ship("Destroyer", 3);
		ships[3] = new Ship("Submarine", 3);
		ships[4] = new Ship("Patrol Boat", 2);
	}
	
	
	/**
	 * @param p the Point at which we are attempting to fire at
	 * @return True If we successfully hit Something(Open Sea or a Ship), false Otherwise 
	 */
	public boolean FireAt(Point p){
		if(spaces[p.y][p.x].getFace() == SpaceFace.FIRE || spaces[p.y][p.x].getFace() == SpaceFace.SPLASH){
			return false;
		} else {
			for(int i = 0; i < NUM_OF_SHIPS; i++){
				if(ships[i].fireAt(p)){
					spaces[p.y][p.x].setFace(SpaceFace.FIRE);
					if(ships[i].isDead()) deadShips++;
					return true;
				}
			}
			spaces[p.y][p.x].setFace(SpaceFace.SPLASH);
			return true;
		}

	
	}

	/**
	 * We will need to go through the number of placedShips 
	 * and Check to see if any of them conflict
	 * We also need to check and make sure that the ship will not
	 * be out of bounds. E.G Will not go off the board.
	 * Finally we need to make sure that player does not click diagonally 
	 * If any of these cases is true we will return a false and the player/computer will
	 * try again to place the ship.
	 * 
	 * Also if the ship placement is succesful we need to check if we are placing this 
	 * on a player board or a computer board. If we are placing it on a player board 
	 * we need to set the spaces the ship to SHIP
	 * Otherwise we will not do so and leave it as a water.
	 * 
	 * @param p - This is where we would like the ship to start
	 * @param direction - This is the direction the ship it.
	 * @return This returns if we succesfully placed the ship
	 */
	public boolean setupNextShipAt(Point p, Point direction){
		if(placedShips < NUM_OF_SHIPS){
			if( (p.x  == direction.x ) || (p.y == direction.y) ){
				// The user is setting up the ship vertical
				if(p.x == direction.x){
					for(int i = 0; i < ships[placedShips].SIZE; i++){
						for(int j = 0; j < placedShips; j++){
							if( p.y > direction.y){
								// The user is placing the ship leftwards.
								// Now we need to check for overlapping
								// ships and if it's in bounds
								if(p.y - i < 0)	return false;
								if(ships[j].isASpot(new Point(p.x, p.y -i))) return false;
							}
							else {
								// The user is placing the ship rightwards.
								// Now we need to check for overlapping
								// ships and if it's in bounds
								if(p.y + i > 9) return false;
								if(ships[j].isASpot(new Point(p.x, p.y +i))) return false;
							}
						}

					}
				}
				// The user is setting up the ship horizontal
				else if(p.y == direction.y){
					for(int i = 0; i < ships[placedShips].SIZE; i++){
						for(int j = 0; j < placedShips; j++){
							// The user is placing the ship up.
							// Now we need to check for overlapping
							// ships and if it's in bounds
							if( p.x > direction.x){
								if(p.x - i < 0) return false;
								if(ships[j].isASpot(new Point(p.x -i, p.y ))) return false;
							}
							// The user is placing the ship down.
							// Now we need to check for overlapping 
						    // ships and if it's in bounds.
							else {
								if(p.x + i > 9) return false;
								if(ships[j].isASpot(new Point(p.x +i, p.y ))) return false;
							}
						}

					}
				}
				try{
					//We now try to place the ship. 
					// If we get any exceptions we will kill
					// the try and simply return a false 
					// which tells the Game class that it 
					// was an unsuccessful attempt.
					ships[placedShips].setupShip(p, direction);
					if(player){
						Point[] temp = ships[placedShips].getPoints();
						for(int i = 0; i < ships[placedShips].SIZE; i++){
							spaces[temp[i].y][temp[i].x].setFace(SpaceFace.SHIP);
						}
					}
					
					placedShips++;
					return true;
					
				} catch (ShipOutOfBoundsException b){
				} catch (DiagonalException d){
				}
			}
		}
		return false;
		
	}
	
	
	/**
	 * Adds the MouseListener to all of the buttons
	 */
	public void addMouseListener(MouseListener m){
		for(int y = 0; y < BOARD_SIZE; y++){
			for(int x = 0; x < BOARD_SIZE; x++){
				spaces[y][x].addMouseListener(m);
			}
		}
		
	}
	/**
	 * Removes the mouseListener from all of thebuttons
	 */
	public void removeMouseListener(MouseListener m){
		for(int y = 0; y < BOARD_SIZE; y++){
			for(int x = 0; x < BOARD_SIZE; x++){
				spaces[y][x].removeMouseListener(m);
			}
		}
	}
	/**
	 * Adds a keylistener to the buttons.
	 * We add it to all of the buttons because there
	 * can only be one focused button and any of the keys 
	 * will likely be a focuded button.
	 */
	public void addKeyListener(KeyListener e){
		for(int y = 0; y < BOARD_SIZE; y++){
			for(int x = 0; x < BOARD_SIZE; x++){
				spaces[y][x].addKeyListener(e);
			}
		}
	}
	
	/**
	 * @return The name of the ships that we are placing
	 */
	public String getCurrentShipToLayDown(){
		if(placedShips < 5){
			return ships[placedShips].NAME;
		} else {
			return "All ships placed";
		}
	}
	/**
	 * 
	 * @return Size of the current ship we are placing down
	 */
	public int getCurrentShipToLayDownSize(){
		if(placedShips < 5){
			return ships[placedShips].SIZE;			
		} else {
			return 0;
		}
	}
	/**
	 * @return number of Ships placed on board. 
	 */
	public int getNumOfShipsOnBoard(){
		return placedShips;
	}
	
	/**
	 * This sets the debug mode
	 * If we are setting to Debug mode
	 * we will want to show were all of the 
	 * ships are for the computer.
	 * 
	 * However, we do not want to write
	 * of the sections that are 
	 * either on fire or is currently a 
	 * splash.
	 * 
	 * Finally we really only to change 
	 * anything if the current player is a
	 * computer or not
	 * 
	 * @return the current debug status
	 */
	
	public boolean areAllShipsDead(){
		return (deadShips == NUM_OF_SHIPS);
	}
	
	/**
	 * We will want to use DebugMode in order
	 * to see the computer's board so we can 
	 * actually test if the game finishes. 
	 * @return the current debug mode;
	 */
	public boolean setDebugMode(){
		if(debugMode){
			for(int i = 0; i < NUM_OF_SHIPS; i++){
				Point[] p = ships[i].getPoints();
				for(int j = 0; j < ships[i].SIZE; j++){
					int x = p[j].x;
					int y = p[j].y;
					
					if(spaces[y][x].getFace() != SpaceFace.FIRE){
						spaces[y][x].setFace(SpaceFace.WATER);
					}
				}
				debugMode = false;
			}
		} else {
			for(int i = 0; i < NUM_OF_SHIPS; i++){
				Point[] p = ships[i].getPoints();
				for(int j = 0; j < ships[i].SIZE; j++){
					int x = p[j].x;
					int y = p[j].y;
					
					if(spaces[y][x].getFace() != SpaceFace.FIRE){
						spaces[y][x].setFace(SpaceFace.SHIP);
					}
				}
				debugMode = false;
			}
			debugMode = true;
		}
		return debugMode;
	}
	public static final int BOARD_SIZE = 10;
	public static final int NUM_OF_SHIPS = 5;
	
	private int placedShips;
	private int deadShips;
	/**
	 * Each Space is the size of the BOARD_SIZE integer;
	 */
	private Space[][] spaces;
	/**
	 * The number of ships is NUM_OF_SHIPS;
	 */
	private Ship[] ships;
	/**
	 * This is type of Player that will be associated with this board. 
	 * This will dictate if the player can see the ships on the board 
	 * or not. 
	 * TRUE = PLAYER'S BOARD
	 * FALSE = COMPUTER'S BOARD
	 */
	private boolean player;
	/**
	 * This dictates what setup mode we are in
	 * If true we want to set ships
	 * If it is false we want to set it up in fireMode;
	 */
	
	private boolean debugMode;
	private boolean setupMode;
	/**
	 * This is if we are in debug mode of not
	 * If we are in debug mode we will want to make 
	 * sure we can see all of the ships on the board.
	 */
	
	public static void main(String[] args) {
		JFrame frame = new JFrame("Board Test");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Board b = new Board(true);
		Point ship = new Point(5, 5);
		Point d = new Point(5, 7);
		
		b.setupNextShipAt(ship, d);
		
		
		frame.add(b);
		frame.pack();
		frame.setVisible(true);
	}
	
}


